package com.alibaba.nacos.naming.utils;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

import javax.net.ssl.*;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.HttpURLConnection;
import java.net.URL;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.HashMap;
import java.util.Map;

@Component
public class HttpUtil {

    private static final Logger log = LoggerFactory.getLogger(HttpUtil.class);

    /**
     * 指定的UTF-8字符集读取字节并将它们解码为字符
     * @param urlStr
     * @param param
     * @param contentType
     * @param timeOut
     * @return
     */
    public Map<String,String> getURLContentPostUTF8(String urlStr, String param, String contentType, int timeOut){
        return getURLContentPost(urlStr, param, contentType, timeOut, "UTF-8","0");
    }

    /**
     * 指定的UTF-8字符集读取字节并将它们解码为字符
     * @param urlStr
     * @param param
     * @param contentType
     * @param timeOut
     * @return
     */
    public Map<String,String> getURLContentPostUTF8CBS(String urlStr,String param,String contentType,int timeOut){
        return getURLContentPost(urlStr, param, contentType, timeOut, "UTF-8","1");
    }

    /**
     * @param urlStr
     * @param contentType
     * @param timeOut
     */
    public Map<String,String> getURLContentGetaddProperty(String urlStr,String contentType,int timeOut,Map<String, String> keyMap) {
        HttpURLConnection connection = null;
        BufferedReader br = null;
        Map<String,String> map = new HashMap<String,String>();
        try {
            URL url = new URL(urlStr);
            connection = (HttpURLConnection) url.openConnection();
            connection.setRequestProperty("accept", "*/*");
            connection.setRequestProperty("Content-Type", contentType);
            connection.setConnectTimeout(timeOut);
            connection.setReadTimeout(timeOut);
            for(String key : keyMap.keySet()) {
                connection.addRequestProperty(key, keyMap.get(key));
            }
            connection.connect();

            br = new BufferedReader(new InputStreamReader(connection.getInputStream(),"UTF-8"));
            StringBuilder sb = new StringBuilder();
            String temp = "";
            while((temp = br.readLine())!=null) {
                sb.append(temp);
            }
            br.close();
            br = null;
            connection.disconnect();
            connection = null;

            map.put("code", "0");
            map.put("msg", sb.toString());
            return map;
        } catch (Exception e) {
            map.put("code", "-1");
            map.put("msg", e.toString());
            log.error("Exception：", e);
            return map;
        } finally {
            if (br != null) {
                try {
                    br.close();
                } catch (IOException e) {
                    log.error("IOException：", e);
                }
            }
            if (connection != null) {
                try {
                    connection.disconnect();
                } catch (Exception e) {
                    log.error("Exception：", e);
                }
            }
        }

    }

    public Map<String,String> getURLContentPostaddProperty(String urlStr,String param,String contentType,int timeOut,String charsetName,Map<String, String> keyMap) {
        HttpURLConnection connection = null;
        PrintWriter out = null;
        BufferedReader br = null;
        Map<String,String> map = new HashMap<String,String>();
        try {
            HostnameVerifier hv = new HostnameVerifier() {
                public boolean verify(String urlHostName, SSLSession session) {
                    return true;
                }
            };

            TrustManager[] tms = new TrustManager[1];
            TrustManager tm = new MyTrustManager();
            tms[0] = tm;

            SSLContext sslc = SSLContext.getInstance("TLS");
            sslc.init(null, tms, null);
            HttpsURLConnection.setDefaultSSLSocketFactory(sslc.getSocketFactory());
            HttpsURLConnection.setDefaultHostnameVerifier(hv);

            URL url = new URL(urlStr);
            connection = (HttpURLConnection) url.openConnection();
            connection.setDoOutput(true);
            connection.setDoInput(true);
            connection.setRequestMethod("POST");
            connection.setUseCaches(false);
            connection.setInstanceFollowRedirects(true);
            connection.setRequestProperty("Content-Type", contentType);
            connection.setConnectTimeout(timeOut);
            connection.setReadTimeout(timeOut);
            if(keyMap != null) {
                for(String key : keyMap.keySet()) {
                    connection.addRequestProperty(key, keyMap.get(key));
                }
            }
            connection.connect();

            out = new PrintWriter(connection.getOutputStream());
            out.write(param);
            out.flush();
            out.close();
            out = null;

            br = new BufferedReader(new InputStreamReader(connection.getInputStream(),charsetName));
            StringBuilder sb = new StringBuilder();
            String temp = "";
            while((temp = br.readLine())!=null) {
                sb.append(temp);
            }
            br.close();
            br = null;
            connection.disconnect();
            connection = null;

            map.put("code", "0");
            map.put("msg", sb.toString());
            return map;
        } catch (Exception e) {
            map.put("code", "-1");
            map.put("msg", e.toString());
            log.error("Exception：", e);
            return map;
        } finally {
            if (out != null) {
                try {
                    out.close();
                } catch (Exception e) {
                    log.error("Exception：", e);
                }
            }
            if (br != null) {
                try {
                    br.close();
                } catch (IOException e) {
                    log.error("IOException：", e);
                }
            }
            if (connection != null) {
                try {
                    connection.disconnect();
                } catch (Exception e) {
                    log.error("Exception：", e);
                }
            }
        }
    }

    public Map<String,String> getURLContentPost(String urlStr,String param,String contentType,int timeOut,String charsetName,String flag) {
        HttpURLConnection connection = null;
        PrintWriter out = null;
        BufferedReader br = null;
        Map<String,String> map = new HashMap<String,String>();
        try {
            HostnameVerifier hv = new HostnameVerifier() {
                public boolean verify(String urlHostName, SSLSession session) {
                    return true;
                }
            };

            TrustManager[] tms = new TrustManager[1];
            TrustManager tm = new MyTrustManager();
            tms[0] = tm;

            SSLContext sslc = SSLContext.getInstance("TLS");
            sslc.init(null, tms, null);
            HttpsURLConnection.setDefaultSSLSocketFactory(sslc.getSocketFactory());
            HttpsURLConnection.setDefaultHostnameVerifier(hv);

            URL url = new URL(urlStr);
            connection = (HttpURLConnection) url.openConnection();
            connection.setDoOutput(true);
            connection.setDoInput(true);
            connection.setRequestMethod("POST");
            connection.setUseCaches(false);
            connection.setInstanceFollowRedirects(true);
            connection.setRequestProperty("Content-Type", contentType);
            if("1".equals(flag))
            {
                connection.setRequestProperty("SOAPAction", "application/soap+xml");
            }
            connection.setConnectTimeout(timeOut);
            connection.setReadTimeout(timeOut);
            connection.connect();

            out = new PrintWriter(connection.getOutputStream());
            out.write(param);
            out.flush();
            out.close();
            out = null;

            br = new BufferedReader(new InputStreamReader(connection.getInputStream(),charsetName));
            StringBuilder sb = new StringBuilder();
            String temp = "";
            while((temp = br.readLine())!=null) {
                sb.append(temp);
            }
            br.close();
            br = null;
            connection.disconnect();
            connection = null;

            map.put("code", "0");
            map.put("msg", sb.toString());
            return map;
        } catch (Exception e) {
            map.put("code", "-1");
            map.put("msg", e.toString());
            log.error("Exception：", e);
            return map;
        } finally {
            if (out != null) {
                try {
                    out.close();
                } catch (Exception e) {
                    log.error("Exception：", e);
                }
            }
            if (br != null) {
                try {
                    br.close();
                } catch (IOException e) {
                    System.out.println("Exception：" + e);
                }
            }
            if (connection != null) {
                try {
                    connection.disconnect();
                } catch (Exception e) {
                    log.error("Exception：", e);
                }
            }
        }
    }

    static class MyTrustManager implements TrustManager, X509TrustManager {
        public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {
        }

        public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {
        }

        public X509Certificate[] getAcceptedIssuers() {
            return null;
        }
    }
}
